package com.kws.tool.util;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONArray;

import com.google.gson.Gson;
import com.kws.tool.enums.ElectronicSignatureUrlEnum;
import org.apache.poi.ss.formula.functions.T;
import org.apache.tomcat.util.codec.binary.Base64;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.MessageFormat;
import java.util.Date;
import java.util.List;

/**
 * <b>ElectronicSignatureHttpUtil</b>
 *
 * @description: ElectronicSignatureHttpUtil <br>
 * @date: 2024/11/11 10:25 <br>
 * @author: lhm <br>
 * @version: 1.0 <br>
 */

public class ElectronicSignatureHttpUtil {
    private static final Logger logger = LoggerFactory.getLogger(ElectronicSignatureHttpUtil.class);

    public static JSONObject electronicSignatureHttpPostUtils(String queryUrl, String appId, String appKey, String json) throws Exception {
        URL url = new URL(ElectronicSignatureUrlEnum.ELECTRONIC_SIGNATURE_URL+queryUrl);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("POST");
        connection.setRequestProperty("Accept", "*/*");
        connection.setRequestProperty("Content-Type","application/json; charset=UTF-8");
        connection.setRequestProperty("X-Tsign-Open-App-Id",appId);
        connection.setRequestProperty("X-Tsign-Open-Auth-Mode","Signature");
        String date = String.valueOf(new Date().getTime());
        //计算签名
        String bodyContentMD5 = getBodyContentMD5(json);
        StringBuffer sb = new StringBuffer();
        sb.append("POST").append("\n").append("*/*").append("\n").append(bodyContentMD5).append("\n")
                .append("application/json; charset=UTF-8").append("\n").append("").append("\n").append(queryUrl);
        String plaintext = sb.toString();
        String reqSignature = doSignatureBase64(plaintext, appKey);
        connection.setRequestProperty("X-Tsign-Open-Ca-Signature",reqSignature);
        connection.setRequestProperty("X-Tsign-Open-Ca-Timestamp",date);
        connection.setRequestProperty("Content-MD5",bodyContentMD5);
        //3.3设置输入输出，因为默认新创建的connection没有读写权限，
        connection.setDoInput(true);
        connection.setDoOutput(true);
        DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());
        if (null != json) {
            outputStream.write(json.getBytes(StandardCharsets.UTF_8));
        }
        outputStream.flush();
        outputStream.close();

        // 发送请求并获取响应码
        int responseCode = connection.getResponseCode();
        String line = null;
        // 检查响应码
        if (responseCode == HttpURLConnection.HTTP_OK) {
            // 读取响应内容
            BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            StringBuilder response = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            reader.close();

            // 处理响应内容
            logger.info("获取电子签章返回结果:{}"+JSONUtil.toJsonStr(response.toString()));
            JSONObject resultJson = JSONUtil.parseObj(response.toString());
            // 关闭连接
            connection.disconnect();
            return resultJson;
        } else {
            // 处理错误响应
            throw new SecurityException("请求失败，请重试！");

        }
    }


    public static JSONObject electronicSignatureHttpGetUtils(String queryUrl,String appId,String appKey,String params) throws Exception {
        URL url = new URL(ElectronicSignatureUrlEnum.ELECTRONIC_SIGNATURE_URL+queryUrl);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");
        connection.setRequestProperty("Accept", "*/*");
        connection.setRequestProperty("Content-Type","application/json; charset=UTF-8");
        connection.setRequestProperty("X-Tsign-Open-App-Id",appId);
        connection.setRequestProperty("X-Tsign-Open-Auth-Mode","Signature");
        String date = String.valueOf(new Date().getTime());
        //计算签名
        String bodyContentMD5 = getBodyContentMD5(params);
        StringBuffer sb = new StringBuffer();
        sb.append("POST").append("\n").append("*/*").append("\n").append(bodyContentMD5).append("\n")
                .append("application/json; charset=UTF-8").append("\n").append("").append("\n").append(queryUrl);
        String plaintext = sb.toString();
        String reqSignature = doSignatureBase64(plaintext, appKey);
        connection.setRequestProperty("X-Tsign-Open-Ca-Signature",reqSignature);
        connection.setRequestProperty("X-Tsign-Open-Ca-Timestamp",date);
        //3.3设置输入输出，因为默认新创建的connection没有读写权限，
        connection.setDoInput(true);
        connection.setDoOutput(true);

        DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());
        outputStream.flush();
        outputStream.close();

        // 发送请求并获取响应码
        int responseCode = connection.getResponseCode();
        String line = null;
        // 检查响应码
        if (responseCode == HttpURLConnection.HTTP_OK) {
            // 读取响应内容
            BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            StringBuilder response = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            reader.close();

            // 处理响应内容
            logger.info("获取电子签章返回结果:{}"+JSONUtil.toJsonStr(response.toString()));
            try{
                JSONObject jsonObject = xml2Json(response.toString());
                if (0 == (int)jsonObject.get("code")){
                    return JSONUtil.parseObj(jsonObject.get("data"));
                }
            }catch (Exception e){
                throw new SecurityException("请求失败，请重试！");
            }
        } else {
            // 处理错误响应
            throw new SecurityException("请求失败，请重试！");

        }
        // 关闭连接
        connection.disconnect();
        return null;
    }



        public static String doSignatureBase64(String message, String secret) throws Exception {
        String algorithm = "HmacSHA256";
        Mac hmacSha256;
        String digestBase64 = null;
        try {
            hmacSha256 = Mac.getInstance(algorithm);
            byte[] keyBytes = secret.getBytes("UTF-8");
            byte[] messageBytes = message.getBytes("UTF-8");
            hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, algorithm));
            // 使用HmacSHA256对二进制数据消息Bytes计算摘要
            byte[] digestBytes = hmacSha256.doFinal(messageBytes);
            // 把摘要后的结果digestBytes使用Base64进行编码
            digestBase64 = new String(Base64.encodeBase64(digestBytes), "UTF-8");
        } catch (NoSuchAlgorithmException e) {
            String msg = MessageFormat.format("不支持此算法: {0}", e.getMessage());
            Exception ex = new Exception(msg);
            ex.initCause(e);
            throw ex;
        } catch (UnsupportedEncodingException e) {
            String msg = MessageFormat.format("不支持的字符编码: {0}", e.getMessage());
            Exception ex = new Exception(msg);
            ex.initCause(e);
            throw ex;
        } catch (InvalidKeyException e) {
            String msg = MessageFormat.format("无效的密钥规范: {0}", e.getMessage());
            Exception ex = new Exception(msg);
            ex.initCause(e);
            throw ex;
        }
        return digestBase64;
    }

    public static JSONObject xml2Json(String xmlStr) throws DocumentException {
        Document doc = DocumentHelper.parseText(xmlStr);
        JSONObject json = new JSONObject();
        dom4j2Json(doc.getRootElement(), json);
        return json;
    }

    public static void dom4j2Json(Element element, JSONObject json) {
        List<Element> chdEl = element.elements();
        for(Element e : chdEl){
            if (!e.elements().isEmpty()) {
                JSONObject chdjson = new JSONObject();
                dom4j2Json(e, chdjson);
                Object o = json.get(e.getName());
                if (o != null) {
                    JSONArray jsona = null;
                    if (o instanceof JSONObject) {
                        JSONObject jsono = (JSONObject) o;
                        json.remove(e.getName());
                        jsona = new JSONArray();
                        jsona.add(jsono);
                        jsona.add(chdjson);
                    }
                    if (o instanceof JSONArray) {
                        jsona = (JSONArray) o;
                        jsona.add(chdjson);
                    }
                    json.put(e.getName(), jsona);
                } else {
                    if (!chdjson.isEmpty()) {
                        json.put(e.getName(), chdjson);
                    }
                }
            } else {
                if (!e.getText().isEmpty()) {
                    json.put(e.getName(), e.getText());
                }
            }
        }
    }

    public static String getBodyContentMD5(String bodyData){
        byte[] md5Bytes = null;
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            md5.update(bodyData.getBytes(StandardCharsets.UTF_8));
            md5Bytes = md5.digest();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return new String(Base64.encodeBase64(md5Bytes));
    }

}
